﻿using Newtonsoft.Json;
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Security.Cryptography;
using System.Text;
using System.Text.RegularExpressions;

namespace HBase {
    /**
   *┌────────────────────────────────────────────────┐
   *│　描    述：ClassUtil                                                    
   *│　作    者：sgj                                              
   *│　版    本：1.0                                              
   *│　创建时间：2021/6/6 9:34:49                        
   *└────────────────────────────────────────────────┘
   **/
    public class HUtil {
        private static readonly ConcurrentDictionary<RuntimeTypeHandle ,string> TypeTableName = new ConcurrentDictionary<RuntimeTypeHandle ,string>();
        private static readonly ConcurrentDictionary<String ,string> strTableName = new ConcurrentDictionary<string ,string>();
        public const int ticksSecRate = 10000 * 1000;
        public const long randSeek = 638184961415926535;


        static char[] c = null;
        static Dictionary<char ,int> Base64Code = new Dictionary<char ,int>();
        static object obj = new object();
        public static readonly long baseTicks;

        public static readonly int bit = 13;
        private static long last = 0;
        static HUtil() {

            String key = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ[]abcdefghijklmnopqrstuvwxyz";
            c = key.ToCharArray();
            for( int i = 0;i < c.Length;i++ ) {
                Base64Code.Add(c[i] ,i);
            }
            baseTicks = new DateTime(2020 ,1 ,1).Ticks >> bit;
        }


        static public void setValue(Object obj ,String name ,Object value) {
            Type t = obj.GetType();
            PropertyInfo info = t.GetProperty(name);
            info.SetValue(obj ,value);
        }

        static public Object getValue(Object obj ,string fieldName) {
            Type t = obj.GetType();

            PropertyInfo info = t.GetProperty(fieldName);
            return info.GetValue(obj);
        }
        static public Dictionary<string ,DateTime> getDate(Object obj) {
            Type t = obj.GetType();
            Dictionary<string ,DateTime> res = new Dictionary<string ,DateTime>();
            PropertyInfo[] fields = t.GetProperties();
            Type tmp = typeof(DateTime);
            foreach( PropertyInfo fi in fields ) {
                if( fi.PropertyType == tmp ) {
                    res.Add(fi.Name ,( DateTime ) fi.GetValue(obj));
                }
            }

            return res;
        }

        public static string GetTableName(Type type) {
            string name;
            if( !TypeTableName.TryGetValue(type.TypeHandle ,out name) ) {
                name = type.Name;
                if( type.IsInterface && name.StartsWith("I") )
                    name = name.Substring(1);
                //NOTE: This as dynamic trick should be able to handle both our own Table-attribute as well as the one in EntityFramework 
                var tableattr = type.GetCustomAttributes(false).Where(attr => attr.GetType().Name == "TableAttribute").SingleOrDefault() as
                    dynamic;
                if( tableattr != null ) {
                    name = tableattr.Name;
                }
                name = camelCase2_(name);
                TypeTableName[type.TypeHandle] = name;
            }
            return name;
        }

        public static String camelCase2_(String className) {
            if( strTableName.ContainsKey(className) ) {

                return strTableName[className];
            }
            string regularExpression = "[A-Z]";
            Regex rg = new Regex(regularExpression);
            StringBuilder tableName = new StringBuilder();
            for( int i = 0;i < className.Length;i++ ) {
                String c = className[i].ToString();
                if( rg.IsMatch(c) && i != 0 ) {
                    tableName.Append("_");
                    tableName.Append(c);
                } else {
                    tableName.Append(c);
                }
            }
            String value = tableName.ToString().ToLower();
            strTableName.TryAdd(className ,value);
            return value;
        }

        public static String formatInt(String str ,params object[] a) {

            for( int i = 0;i < a.Length;i++ ) {
                a[i] = ( int ) a[i];
            }
            return String.Format(str ,a);


        }


        public static string mySerializeObject(object o) {
            string json = JsonConvert.SerializeObject(o);
            return json.Replace("\r\n" ,"");
        }
        public static string toView(Object obj) {
            if( obj == null ) {
                return "";
            }
            String josn = mySerializeObject(obj);
            return unUseJson(josn);
        }
        public static string toJosn(Object obj) {
            if( obj == null ) {
                return "";
            }
            String josn = mySerializeObject(obj);
            return unUseJson(josn);
        }

        public static T toObj<T>(String jsonStr) {
            if( string.IsNullOrEmpty(jsonStr) ) {
                return default(T);
            }
            return Newtonsoft.Json.JsonConvert.DeserializeObject<T>(jsonStr);
        }

        public static String unUseJson(String v) {
            String res = $"\"";
            String param = v.Replace(res ,"");
            if( param.Length >= 2 ) {
                param = param.Substring(1 ,param.Length - 2);
            }
            return param.Replace(" " ,"");
        }

        public static string MD5Encrypt(string strText) {
            MD5CryptoServiceProvider md5Hasher = new MD5CryptoServiceProvider();
            byte[] data = md5Hasher.ComputeHash(Encoding.Default.GetBytes(strText));
            StringBuilder sBuilder = new StringBuilder();
            for( int i = 0;i < data.Length;i++ ) {
                sBuilder.Append(data[i].ToString("x2"));
            }
            return sBuilder.ToString();
        }

        public static string to64(long xx) {
            if( xx == 0 ) {
                return "0";
            }
            string a = "";
            while( xx >= 1 ) {
                int index = ( int ) (xx & 63);
                xx >>= 6;
                a = c[index] + a;
            }
            return a;
        }
        public static string to64() {
            lock( obj ) {
                long xx = DateTime.Now.Ticks;
                xx = xx >> bit;
                xx -= baseTicks;

                if( last >= xx ) {
                    last++;
                } else {
                    last = xx;
                }
                xx = last;



                return to64(xx);
            }
        }
        public static long toLong(string xx) {
            long a = 0;
            int power = xx.Length;
            for( int i = 0;i < power;i++ ) {
                a <<= 6;
                char key = xx[i];
                a += Base64Code[key];

            }
            return a;
        }

        public static DateTime toDate(String xx) {
            long x = toLong(xx);
            x += baseTicks;
            x = x << bit;
            return new DateTime(x);

        }



        static int rand = (int)DateTime.Now.Ticks;
        public static int getNext(int f ,int t) {
            Random r = new Random(rand);
            rand= r.Next(f,t);
            return rand;
        }
    }
}
